library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity mult is
generic (N : integer := 32);
port (A 		: in  std_logic_vector (N/2-1 downto 0);
		B 		: in  std_logic_vector (N/2-1 downto 0);
		M		: out std_logic_vector (N-1 downto 0)
);
end entity;

architecture Structural of mult is
    
type SignalVector is array (N/4-1 downto 0) of std_logic_vector (N-1 downto 0);
type SignalSel is array (N/4-1 downto 0) of std_logic_vector (2 downto 0);

component booth_mux is
generic (N : integer := 16);
port( M0  	: in  std_logic_vector (N-1 downto 0);
      M1  	: in  std_logic_vector (N-1 downto 0);
      M2  	: in  std_logic_vector (N-1 downto 0);
      M3  	: in  std_logic_vector (N-1 downto 0);
      M4  	: in  std_logic_vector (N-1 downto 0);
      SEL 	: in  std_logic_vector (2 downto 0);
      MOUT	: out std_logic_vector (N-1 downto 0)
);
end component;

component ADDER is
generic (N : integer := 32);
port(	A		: in  std_logic_vector (N-1 downto 0);
		B		: in  std_logic_vector (N-1 downto 0);
		C_in	: in  std_logic;
		SUB	: in  std_logic;
		OVF	: out std_logic;
		S		: out std_logic_vector (N-1 downto 0)
);
end component;
  
	signal muxout  : SignalVector;
	signal sumout  : SignalVector;
	signal zeros   : std_logic_vector (N-1 downto 0);
	signal nA      : std_logic_vector (N/2-1 downto 0);
	
   signal M1_i  	: SignalVector;
   signal M2_i  	: SignalVector;
   signal M3_i  	: SignalVector;
   signal M4_i  	: SignalVector;
   signal SEL_i 	: SignalSel;

   
begin      
   
	zeros <= (others=>'0');
	
	oneadder: ADDER generic map (N/2) port
		map (	A		=> not A,
				B		=> zeros(N/2-1 downto 0),
				C_in	=> '1',
				SUB	=> '0',
				OVF	=> open,
				S		=> nA
		);
	--nA <= not(A) + 1;
	--riga0: if riga = 0 generate
			M1_i(0)(N-1   downto N/2)   <= (others => '0');
	      M1_i(0)(N/2-1 downto 0)     <= A;
	      M2_i(0)(N-1   downto N/2)   <= (others => nA(N/2-1)); --sign extension
	      M2_i(0)(N/2-1 downto 0)     <= nA;
	      M3_i(0)(N-1   downto N/2+1) <= (others => '0');
	      M3_i(0)(N/2   downto 1)     <= A;
	      M3_i(0)(0)                  <= '0';
	      M4_i(0)(N-1   downto N/2+1) <= (others => nA(N/2-1));
	      M4_i(0)(N/2   downto 1)     <= nA;
	      M4_i(0)(0)                  <= '0';
	      SEL_i(0)                    <= (B(1),B(0),'0');

		   enc0: booth_mux generic map(N) port
				map (	M0   => zeros,
						M1   => M1_i(0),
                  M2   => M2_i(0),
                  M3   => M3_i(0),
                  M4   => M4_i(0),
                  SEL  => SEL_i(0),
                  MOUT => sumout(0)
            ); 
	--	end generate riga0;

	righe: for riga in 1 to N/4-1 generate
		
       
     -- rigan0: if riga /=0 generate
			M1_i(riga)(N-1          downto N/2+2*riga)     <= (others => '0');
         M1_i(riga)(N/2+2*riga-1 downto 2*riga)         <= A;
         M1_i(riga)(2*riga-1     downto 0)              <= (others => '0');
         M2_i(riga)(N-1          downto N/2+2*riga)     <= (others => nA(N/2-1));
         M2_i(riga)(N/2+2*riga-1 downto 2*riga)         <= nA;
         M2_i(riga)(2*riga-1     downto 0)              <= (others => '0');
         M3_i(riga)(N-1          downto N/2+(2*riga)+1) <= (others => '0');
         M3_i(riga)(N/2+2*riga   downto 2*riga+1)       <= A;
         M3_i(riga)(2*riga       downto 0)              <= (others => '0');
         M4_i(riga)(N-1          downto N/2+(2*riga)+1) <= (others => nA(N/2-1));
         M4_i(riga)(N/2+2*riga   downto 2*riga+1)       <= nA;
         M4_i(riga)(2*riga       downto 0)              <= (others => '0');
			
         SEL_i(riga) <= B(riga*2+1) & B(riga*2) & B(riga*2-1);
          
         enc: booth_mux generic map (N) port 
				map ( M0   => zeros,
                  M1   => M1_i(riga),
                  M2   => M2_i(riga),
                  M3   => M3_i(riga),
                  M4   => M4_i(riga),
                  SEL  => SEL_i(riga),
                  MOUT => muxout(riga-1)
            );
        
			sum: ADDER generic map (N) port
				map (	A		=> muxout(riga-1),
						B		=> sumout(riga-1),
						C_in	=> '0',
						SUB	=> '0',
						OVF	=> open,
						S		=> sumout(riga)
				);		 
			 
     -- end generate rigan0;
	end generate righe;
  
	M <= sumout(N/4-1);              
			 
end Structural;
